package org.robot.scm.platform;

import cn.hutool.core.lang.Pair;
import com.google.common.collect.Maps;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Timer;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.robot.scm.pojos.config.BaseConfig;
import org.robot.scm.pojos.BaseNotify;
import org.robot.scm.pojos.config.MainConfig;
import org.robot.scm.pojos.config.base.BasePlatform;
import org.robot.scm.pojos.enums.PlatformEnum;
import org.robot.scm.utils.JsonHelper;
import org.robot.scm.utils.SendNoticeHelper;

@Slf4j
public abstract class AbstractMonitor {

    @Getter
    private static final List<? extends AbstractMonitor> monitors = ReflectionLoader.load(AbstractMonitor.class);

    /**
     * 核心任务逻辑
     */
    private static final Map<PlatformEnum, Pair<Timer, DefaultScheduler>> coreTask = Maps.newConcurrentMap();

    /**
     * 主配置
     */
    public static MainConfig mainConfig;

    public static void start() {
        monitors.forEach(AbstractMonitor::run);
    }

    /**
     * 当前平台
     */
    public abstract PlatformEnum getPlatform();

    /**
     * 读取原始最新公告
     */
    public abstract BaseNotify doMonitor(BaseConfig config);

    /**
     * 有通知后额外处理逻辑
     */
    public void doAfter(BaseConfig config, BaseNotify notice) {

    }

    /**
     * 初始化平台配置
     */
    public static void cfg(String configPath) {
        try {
            String jsonConfig = FileUtils.readFileToString(new File(configPath), StandardCharsets.UTF_8.name());
            mainConfig = JsonHelper.toObject(jsonConfig, MainConfig.class, new MainConfig());
        } catch (Exception e) {
            log.error("read config error", e);
        }
    }

    /**
     * 读取当前平台的配置信息
     */
    @SneakyThrows
    public BaseConfig getTargetConfig() {
        BasePlatform currentPlatform = mainConfig.getPlatform(getPlatform());
        return new BaseConfig(mainConfig, currentPlatform);
    }

    /**
     * 执行入口
     */
    public void run() {
        BaseConfig config = this.getTargetConfig();
        if (!config.get().getEnables().contains(getPlatform().getVal())) {
            return;
        }
        log.info(getPlatform().getVal().concat(" server started ... ok"));

        //运行任务
        this.doHandle(config);
    }

    public void refresh(String configPath) {
        // 重新读取配置信息
        cfg(configPath);

        // 当前平台配置
        BaseConfig config = this.getTargetConfig();

        // 当前平台执行器
        Pair<Timer, DefaultScheduler> corePair = coreTask.get(getPlatform());

        // 刷新当前配置信息
        if (Objects.nonNull(corePair)) {
            corePair.getValue().refreshConfig(config);
        }

        // 任务配置已关闭，但是任务信息还在执行则强制停止
        if (!config.get().getEnables().contains(getPlatform().getVal()) && Objects.nonNull(corePair)) {
            log.info(getPlatform().getVal().concat(" server stopped ... ok"));
            corePair.getKey().cancel();
            coreTask.remove(getPlatform());
        }

        // 任务配置已开启，但是任务信息没有运行则开启
        if (config.get().getEnables().contains(getPlatform().getVal()) && Objects.isNull(corePair)) {
            log.info(getPlatform().getVal().concat(" server started ... ok"));
            this.doHandle(config);
        }
    }

    /**
     * 处理任务
     */
    private void doHandle(BaseConfig config) {
        long period = config.getCurrentPlatform().getCheckSeconds() * 1000L;
        DefaultScheduler scheduler = new DefaultScheduler(this, config);
        Timer coreTimer = new Timer();
        coreTimer.scheduleAtFixedRate(scheduler, 0, period);

        // 缓存运行信息
        coreTask.put(getPlatform(), Pair.of(coreTimer, scheduler));
    }

    /**
     * 当前平台获取到了最新通知，发送给谁
     */
    public void doSend(BaseConfig config, BaseNotify notice) {
        SendNoticeHelper.sendNotice(config, notice, getPlatform());
    }

    /**
     * 过滤一天
     */
    protected boolean filter(long date) {
        return System.currentTimeMillis() - date < 86400000L;
    }
}
